package com.ruoyi.web.controller.wind;


import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.exception.ProcessStopException;
import com.ruoyi.common.utils.ExecUtil;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.SseEmitterUtils;
import com.ruoyi.common.utils.bean.ObjUtil;
import com.ruoyi.common.utils.biz.CommonUtil;
import com.ruoyi.common.utils.biz.PathUtil;
import com.ruoyi.common.utils.biz.ResultSaveModule;
import com.ruoyi.web.server.entity.ResultSave;
import com.ruoyi.web.server.entity.WindRetrievalCal;
import com.ruoyi.web.server.service.ResultSaveService;
import com.ruoyi.web.vo.WindRetrievalCalVo;
import com.ruoyi.web.vo.WindRetrievalDrawVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;


/**
 * <p>
 *  风场反演
 * </p>
 *
 * @author liuhl
 * @since 2024-04-15
 */
@RestController
@RequestMapping("/retrieval")
@AllArgsConstructor
@Slf4j
@Api(tags = "风场反演")
public class WindRetrievalController {

    private ResultSaveService resultSaveService;

    public static void main(String[] args) {
        WindRetrievalCalVo vo = new WindRetrievalCalVo();
        vo.setMonth("12");
        vo.setMethod("linear");
        vo.setType("radar");
        String str = ObjUtil.toStr(vo);
        System.out.println(str);
    }

    @PostMapping("/cal")
    @ApiOperation(value = "风场反演-计算", notes = "根据页面入参计算出结果文件", httpMethod = "POST")
    public AjaxResult windRetrievalCal(@RequestBody WindRetrievalCalVo vo) throws ProcessStopException {
        log.debug("风场反演-计算-入参:{}", vo);
        //王姐说，这一块的存储都是涉及数据收集的
        String configPath = PathUtil.commonIniPath();

        String tmpDir = PathUtil.tmpDir() +
                PathUtil.moduleDirs().getCollect().get("dir");

        String outputDir = PathUtil.outputDir() +
                PathUtil.moduleDirs().getCollect().get("dir") +
                PathUtil.moduleDirs().getCollect().get("result");

        String type = vo.getType();
        String area = CommonUtil.getArea(vo.getLongitudeRange(), vo.getLatitudeRange());
        String sseId = vo.getSseId()+SecurityUtils.getLoginUser().getUsername();

        if ("daily".equals(type)){  //日观测数据

            String codePath = PathUtil.codeDir() +
                    PathUtil.moduleDirs().getModelRevise().get("dir") +
                    PathUtil.moduleDirs().getModelRevise().get("daily");

            List<String> command = Stream.of("python",
                    "-u",
                    codePath,
                    outputDir,  //两次是因为一个作为读取源文件的路径，一个作为生成新文件的路径
                    outputDir,
                    tmpDir,
                    vo.getStartTime(),
                    vo.getEndTime(),
                    area,
                    vo.getMethod()
                    ).collect(Collectors.toList());

            String results = ExecUtil.execPython(command, sseId);
            SseEmitterUtils.remove(sseId);
            if (results == null || !results.contains("###")){
                return AjaxResult.error(results);
            }
            String[] splitArr = results.split("###");

            List<String> resultDataList = Arrays.asList(splitArr).stream()
                    .filter(path -> path.contains(".nc"))
                    .map(String::trim)
                    .collect(Collectors.toList());

            List<String> fileNameList = resultDataList
                    .stream()
                    .map(filePath -> filePath.substring(filePath.lastIndexOf("/") + 1))
                    .collect(Collectors.toList());
            String fileNames = JSONUtil.toJsonStr(fileNameList);

            ResultSave resultSave = ResultSave.builder()
                    .params(ObjUtil.toStr(vo))
                    .resultData(JSONUtil.toJsonStr(resultDataList))
                    .fileNames(fileNames)
                    .startTime(vo.getStartTime())
                    .endTime(vo.getEndTime())
                    .module(ResultSaveModule.MODEL_REVISE)
                    .submodule(ResultSaveModule.MODEL_REVISE_RETRIEVAL)
                    .createTime(new Date())
                    .build();

            resultSaveService.save(resultSave);

            Map<String,Object> resultMap = new LinkedHashMap<>();

            resultMap.put("resultData", JSONUtil.toJsonStr(resultDataList));
            resultMap.put("module", ResultSaveModule.MODEL_REVISE);
            resultMap.put("submodule", ResultSaveModule.MODEL_REVISE_RETRIEVAL);

            return AjaxResult.success(resultMap);
        }

        if ("monthly".equals(type)){ //月平均数据计算

            String codePath = PathUtil.codeDir() +
                    PathUtil.moduleDirs().getModelRevise().get("dir") +
                    PathUtil.moduleDirs().getModelRevise().get("monthly");

            String year = "[" + vo.getStartTime() + "," + vo.getEndTime() + "]";

            String month = vo.getMonth();
            List<String> monthList = Arrays.asList(month.split(","))
                    .stream()
                    .filter(StrUtil::isNotBlank)
                    .collect(Collectors.toList());
            //如果月份只有一个5，就是时间范围为5月，但是给python要传成 [5,5]
            if (monthList.size() == 1) {
                month = "[" + vo.getMonth() + "," + vo.getMonth() + "]";
            }else {
                month = "[" + vo.getMonth() + "]";
            }

            List<String> command = Stream.of("python",
                    "-u",
                    codePath,
                    outputDir,  //两次是因为一个作为读取源文件的路径，一个作为生成新文件的路径
                    outputDir,
                    tmpDir,
                    year,
                    month,
                    area,
                    vo.getCalType(),
                    vo.getMethod()
            ).collect(Collectors.toList());
            String results = ExecUtil.execPython(command, sseId);
            SseEmitterUtils.remove(sseId);
            if (results == null || !results.contains("###")){
                return AjaxResult.error(results);
            }

            String[] splitArr = results.split("###");

            List<String> resultDataList = Arrays.asList(splitArr).stream()
                    .filter(path -> path.contains(".nc"))
                    .map(String::trim)
                    .collect(Collectors.toList());

            List<String> fileNameList = resultDataList
                    .stream()
                    .map(filePath -> filePath.substring(filePath.lastIndexOf("/") + 1))
                    .collect(Collectors.toList());
            String fileNames = JSONUtil.toJsonStr(fileNameList);

            ResultSave resultSave = ResultSave.builder()
                    .params(ObjUtil.toStr(vo))
                    .resultData(JSONUtil.toJsonStr(resultDataList))
                    .fileNames(fileNames)
                    .startTime(vo.getStartTime())
                    .endTime(vo.getEndTime())
                    .module(ResultSaveModule.MODEL_REVISE)
                    .submodule(ResultSaveModule.MODEL_REVISE_RETRIEVAL)
                    .createTime(new Date())
                    .build();

            resultSaveService.save(resultSave);

            Map<String,Object> resultMap = new LinkedHashMap<>();

            resultMap.put("resultData", JSONUtil.toJsonStr(resultDataList));
            resultMap.put("module", ResultSaveModule.MODEL_REVISE);
            resultMap.put("submodule", ResultSaveModule.MODEL_REVISE_RETRIEVAL);

            return AjaxResult.success(resultMap);
        }
        return AjaxResult.error("未知计算类型type:"+type);
    }


    @PostMapping("/draw")
    @ApiOperation(value = "风场反演-绘制", notes = "根据页面入参计算出结果文件", httpMethod = "POST")
    public AjaxResult windRetrievalDraw(@RequestBody WindRetrievalDrawVo vo) {
        log.debug("风场反演-绘制-入参:{}", vo);
        String tmpDir = PathUtil.tmpDir() +
                PathUtil.moduleDirs().getModelRevise().get("dir");
        String outputDir = PathUtil.outputDir() +
                PathUtil.moduleDirs().getCollect().get("dir") +
                PathUtil.moduleDirs().getCollect().get("result");

        String type = vo.getType();
        String dataType = "daily".equals(type)?type:"avg";
        String element = vo.getFactor();  // "['u','v']"
        String level = !"horizon".equals(vo.getResultType())?"all":vo.getLevel();
        String area = CommonUtil.getArea(vo.getLongitudeRange(), vo.getLatitudeRange());

        String codePath = PathUtil.codeDir() +
                PathUtil.moduleDirs().getModelRevise().get("dir") +
                PathUtil.moduleDirs().getModelRevise().get("picture");
        String command = "python "+codePath+" "+outputDir+" "+tmpDir+" "+dataType+" "+vo.getTime()
                +" "+element+" "+level+" "+vo.getResultType()+" "+area+" "+vo.getMethod();
        String results = ExecUtil.execCmdWithResult(command);
        if (results == null || !results.contains("###")){
            return AjaxResult.error(results);
        }
        String[] splitArr = results.split("###");
        return AjaxResult.success("",splitArr[1]);

    }

    @ApiOperation(value = "建立连接", notes = "建立连接")
    @GetMapping(path = "subscribe", produces = {MediaType.TEXT_EVENT_STREAM_VALUE})
    public SseEmitter push(String id, String flag) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        return SseEmitterUtils.connect(id+loginUser.getUsername(), flag);
    }



}
